home *** CD-ROM | disk | FTP | other *** search
/ Informática Multimedia 1995 April / Informatica Multimedia CD - Epimundo.iso / DOS / ARCHIVE / ZIPDEL.ZIP / ZIPDEL.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1989-05-23  |  33.4 KB  |  940 lines

  1. PROGRAM ZIPDel (InFileSpec, Options);
  2.  
  3. {$B-,D+,R-,S-,V-}
  4.  
  5. USES TpCrt,TPDos,TPString,TPSpl,Dos;
  6.  
  7. CONST
  8.   No         = False;
  9.   Yes        = True;
  10.   Bell       = #7;
  11.   ArrayLimit = 1024;
  12.   NL         = #13#10;
  13.  
  14. TYPE
  15.   Line      = STRING[65];
  16.  
  17.   List      = RECORD
  18.                 Name  : STRING[12];
  19.                 Place : LONGINT;
  20.                 ASize : LONGINT;
  21.                 OSize : LONGINT;
  22.                 Date  : WORD;
  23.                 Time  : WORD;
  24.                 Group : BYTE;
  25.               END;
  26.  
  27.   BigArray  = ARRAY [1..ArrayLimit] OF List;
  28.  
  29.   NPtr      = ^Dir_Rec;
  30.   Dir_Rec   = RECORD
  31.                 Name : string[12];
  32.                 Next : NPtr;
  33.                 Prev : NPtr;
  34.               END;
  35.  
  36.   Time_Date  = ARRAY [1..2] OF WORD;
  37.  
  38. VAR
  39.   InFile      : FILE;
  40.   OutFile     : FILE;
  41.   InFileSpec  : Line;
  42.   InFileName  : Line;
  43.   InPath      : Line;
  44.   DirToClean  : Line;
  45.   Version     : Line;
  46.   HeapPtr     : MarkRec;              { Pointer to heap for mark/release   }
  47.   ListArray   : BigArray;
  48.   ZIPCount    : WORD;
  49.   NamePtr     : NPtr;
  50.   Verify      : BOOLEAN;
  51.   Test        : BOOLEAN;
  52.   ForceDel    : BOOLEAN;
  53.   DelFromZIP  : BOOLEAN;
  54.   Match       : WORD;
  55.   Output      : TEXT;
  56.   FileNdx     : WORD;
  57.  
  58. (*----------------------------------------------------------------------*)
  59. (*         Display_ZIP_Contents --- Display contents of ZIP file        *)
  60. (*----------------------------------------------------------------------*)
  61.  
  62. PROCEDURE Display_ZIP_Contents( ZIPFileName : String ; Var ZipFile : File );
  63.  
  64. (*----------------------------------------------------------------------*)
  65. (*                                                                      *)
  66. (*  Procedure: Display_ZIP_Contents                                     *)
  67. (*                                                                      *)
  68. (*  Purpose:   Displays contents of a ZIP file                          *)
  69. (*                                                                      *)
  70. (*  Calling sequence:                                                   *)
  71. (*                                                                      *)
  72. (*  Display_ZIP_Contents( ZIPFileName : String ; Var Zipfile : File);   *)
  73. (*                                                                      *)
  74. (*          ZIPFileName --- name of ZIP file whose contents are to be   *)
  75. (*                          listed.                                     *)
  76. (*                                                                      *)
  77. (*          ZipFile - Handle of Zipfile to be read                      *)
  78. (*                                                                      *)
  79. (*                                                                      *)
  80. (*                                                                      *)
  81. (*----------------------------------------------------------------------*)
  82.  
  83. (*----------------------------------------------------------------------*)
  84. (*               Map of ZIP file entry headers                          *)
  85. (*----------------------------------------------------------------------*)
  86.  
  87. CONST
  88.    ZIP_Central_Header_Signature  = $02014B50;
  89.    ZIP_Local_Header_Signature    = $04034B50;
  90.    ZIP_End_Central_Dir_Signature = $06054B50;
  91.  
  92.    Open_Error    = 1               (* Error when opening file      *);
  93.    Format_Error  = 2               (* Library format bad           *);
  94.    End_Of_File   = 3               (* End of library directory     *);
  95.    Too_Many_Subs = 4               (* Too many nested subdirs      *);
  96.    Central_Dir_Found  = 5          (* Central directory sign found *);
  97.  
  98. TYPE
  99.                                    (* Structure of a local file header *)
  100.    ZIP_Local_Header_Type =
  101.       RECORD
  102.          Signature           : LONGINT  (* Header signature        *);
  103.          Version             : WORD     (* Vers. needed to extract *);
  104.          BitFlag             : WORD     (* General flags           *);
  105.          CompressionMethod   : WORD     (* Compression type used   *);
  106.          FileTime            : WORD     (* File creation time      *);
  107.          FileDate            : WORD     (* File creation date      *);
  108.          CRC32               : LONGINT  (* 32-bit CRC of file      *);
  109.          CompressedSize      : LONGINT  (* Compressed size of file *);
  110.          UnCompressedSize    : LONGINT  (* Original size of file   *);
  111.          FileNameLength      : WORD     (* Length of file name     *);
  112.          ExtraFieldLength    : WORD     (* Length of extra stuff   *);
  113.       END;
  114.  
  115.                                    (* Structure of the central *)
  116.                                    (* directory record         *)
  117.    ZIP_Central_Header_Type =
  118.       RECORD
  119.           Signature           : LONGINT (* Header signature        *);
  120.           VersionMadeBy       : WORD    (* System id/program vers. *);
  121.           VersionNeeded       : WORD    (* Vers. needed to extract *);
  122.           BitFlag             : WORD    (* General flags           *);
  123.           CompressionMethod   : WORD    (* Compression type used   *);
  124.           FileTime            : WORD    (* File creation time      *);
  125.           FileDate            : WORD    (* File creation date      *);
  126.           CRC32               : LONGINT (* 32-bit CRC of file      *);
  127.           CompressedSize      : LONGINT (* Compressed size of file *);
  128.           UnCompressedSize    : LONGINT (* Original size of file   *);
  129.           FileNameLength      : WORD    (* Length of file name     *);
  130.           ExtraFieldLength    : WORD    (* Length of extra stuff   *);
  131.           CommentFieldLength  : WORD    (* Length of comments      *);
  132.           DiskStartNumber     : WORD    (* Disk # file starts on   *);
  133.           InternalAttributes  : WORD    (* Text/non-text flags     *);
  134.           ExternalAttributes  : LONGINT (* File system attributes  *);
  135.           LocalHeaderOffset   : LONGINT (* Where local hdr starts  *);
  136.       END;
  137.  
  138. VAR
  139.  
  140.    ZIP_Entry     : ZIP_Central_Header_Type (* Central header       *);
  141.    ZIP_Pos       : LONGINT      (* Current byte offset in ZIP file *);
  142.    Bytes_Read    : INTEGER      (* # bytes read from ZIP file file *);
  143.    Ierr          : INTEGER      (* Error flag                      *);
  144.    Do_Blank_Line : BOOLEAN      (* TRUE to print blank line        *);
  145.    File_Name     : String       (* File name of entry in ZIP file  *);
  146.    Long_Name     : String       (* Long file name                  *);
  147.  
  148. (*----------------------------------------------------------------------*)
  149. (* Get_Next_ZIP_Local_Header --- Get next local header in ZIP file      *)
  150. (*----------------------------------------------------------------------*)
  151.  
  152. FUNCTION Get_Next_ZIP_Local_Header( VAR ZIP_Local_Header :
  153.                                         ZIP_Local_Header_Type;
  154.                                     VAR Error : INTEGER  ) : BOOLEAN;
  155.  
  156. (*----------------------------------------------------------------------*)
  157. (*                                                                      *)
  158. (*    Function:  Get_Next_ZIP_Local_Header                              *)
  159. (*                                                                      *)
  160. (*    Purpose:   Gets next local header record in ZIP file              *)
  161. (*                                                                      *)
  162. (*    Calling sequence:                                                 *)
  163. (*                                                                      *)
  164. (*       OK := Get_Next_ZIP_Local_Header( VAR ZIP_Local_Header:         *)
  165. (*                                            ZIP_Local_Header_Type;    *)
  166. (*                                        VAR Error : INTEGER ) :       *)
  167. (*                                        BOOLEAN;                      *)
  168. (*                                                                      *)
  169. (*          ZIP_Local_Header --- Local header data                      *)
  170. (*          Error            --- Error flag                             *)
  171. (*          OK               --- TRUE if header successfully found      *)
  172. (*                                                                      *)
  173. (*----------------------------------------------------------------------*)
  174.  
  175. VAR
  176.    ZIP_Local_Hdr    : ZIP_Local_Header_Type   (* Local header         *);
  177.  
  178. BEGIN (* Get_Next_ZIP_Local_Header *)
  179.  
  180.                                    (* Assume no error to start       *)
  181.    Error := 0;
  182.                                    (* Position file                  *)
  183.    Seek( ZIPFile , ZIP_Pos );
  184.                                    (* Read in the file header entry. *)
  185.  
  186.    IF ( IOResult <> 0 ) THEN
  187.       Error := Format_Error
  188.  
  189.    ELSE
  190.       BEGIN
  191.  
  192.          BlockRead( ZIPFile, ZIP_Local_Header, SIZEOF( ZIP_Local_Header ),
  193.                     Bytes_Read );
  194.  
  195.                                    (* If wrong size read, or header marker *)
  196.                                    (* byte is incorrect, report ZIP file   *)
  197.                                    (* format error.                        *)
  198.  
  199.           IF (ZIP_Pos = 0) AND
  200.              ( ZIP_Local_Header.Signature <> ZIP_Local_Header_Signature) THEN
  201.               Bytes_Read :=0;
  202.                                    (* Check to see if this is a ZIP file   *)
  203.  
  204.          IF ( ( IOResult <> 0 ) OR
  205.               ( Bytes_Read < SIZEOF( ZIP_Local_Header_Type ) ) ) THEN
  206.             Error := Format_Error
  207.          ELSE
  208.                                     (* Check for a legitimate header type  *)
  209.  
  210.             IF ( ZIP_Local_Header.Signature = ZIP_Local_Header_Signature ) THEN
  211.                BEGIN (* Local header -- skip it and associated data *)
  212.  
  213.                   ZIP_Pos := ZIP_Pos + ZIP_Local_Header.FileNameLength +
  214.                                        ZIP_Local_Header.ExtraFieldLength +
  215.                                        ZIP_Local_Header.CompressedSize +
  216.                                        SIZEOF( Zip_Local_Header_Type );
  217.                END
  218.  
  219.             ELSE IF ( ZIP_Local_Header.Signature = ZIP_Central_Header_Signature ) THEN
  220.                BEGIN (* Central header -- we want this *)
  221.  
  222.                   Error := Central_Dir_Found;
  223.  
  224.                END
  225.  
  226.             ELSE IF ( ZIP_Local_Header.Signature = ZIP_End_Central_Dir_Signature ) THEN
  227.                Error := End_Of_File;
  228.  
  229.       END;
  230.                                     (* Report success/failure to calling *)
  231.                                     (* routine.                          *)
  232.  
  233.    Get_Next_ZIP_Local_Header := ( Error = 0 );
  234.  
  235. END   (* Get_Next_ZIP_Local_Header *);
  236.  
  237. (*----------------------------------------------------------------------*)
  238. (*     Get_Next_ZIP_Entry --- Get next header entry in ZIP file         *)
  239. (*----------------------------------------------------------------------*)
  240.  
  241. FUNCTION Get_Next_ZIP_Entry( VAR ZIP_Entry : ZIP_Central_Header_Type;
  242.                              VAR FileName  : String;
  243.                              VAR Error     : INTEGER  ) : BOOLEAN;
  244.  
  245. (*----------------------------------------------------------------------*)
  246. (*                                                                      *)
  247. (*    Function:  Get_Next_ZIP_Entry                                     *)
  248. (*                                                                      *)
  249. (*    Purpose:   Gets header information for next file in ZIP file      *)
  250. (*                                                                      *)
  251. (*    Calling sequence:                                                 *)
  252. (*                                                                      *)
  253. (*       OK := Get_Next_ZIP_Entry( VAR ZIP_Entry :                      *)
  254. (*                                     ZIP_Central_Header_Type;         *)
  255. (*                                 VAR FileName  : String;              *)
  256. (*                                 VAR Error     : INTEGER ) : BOOLEAN; *)
  257. (*                                                                      *)
  258. (*          ZIP_Entry --- Header data for next file in ZIP file         *)
  259. (*          FileName  --- File name for this entry                      *)
  260. (*          Error     --- Error flag                                    *)
  261. (*          OK        --- TRUE if header successfully found, else FALSE *)
  262. (*                                                                      *)
  263. (*----------------------------------------------------------------------*)
  264.  
  265. VAR
  266.    L     : INTEGER;
  267.    L_Get : INTEGER;
  268.    L_Got : INTEGER;
  269.  
  270. BEGIN (* Get_Next_ZIP_Entry *)
  271.                                    (* Assume no error to start       *)
  272.    Error := 0;
  273.                                    (* Position file                  *)
  274.    Seek( ZIPFile , ZIP_Pos );
  275.                                    (* Read in the file header entry. *)
  276.  
  277.    IF ( IOResult <> 0 ) THEN
  278.       Error := Format_Error
  279.  
  280.    ELSE
  281.       BEGIN
  282.  
  283.          BlockRead( ZIPFile, ZIP_Entry, SIZEOF( ZIP_Central_Header_Type ),
  284.                     Bytes_Read );
  285.  
  286.                                    (* If wrong size read, or header marker *)
  287.                                    (* byte is incorrect, report ZIP file   *)
  288.                                    (* format error.                        *)
  289.  
  290.          IF ( ( IOResult <> 0 ) OR
  291.               ( Bytes_Read < SIZEOF( ZIP_Central_Header_Type ) ) ) THEN
  292.             Error := Format_Error
  293.          ELSE
  294.                                     (* Check for a legitimate header type  *)
  295.  
  296.             IF ( ZIP_Entry.Signature = ZIP_Central_Header_Signature ) THEN
  297.                BEGIN (* Central header -- we want this *)
  298.  
  299.                                    (* Pick up file name length.       *)
  300.                                    (* Only first 255 chars retrieved. *)
  301.  
  302.                   L := ZIP_Entry.FileNameLength;
  303.  
  304.                   IF ( L > 255 ) THEN
  305.                      L_Get := 255
  306.                   ELSE
  307.                      L_Get := L;
  308.  
  309.                                    (* Read file name characters. *)
  310.  
  311.                   BlockRead( ZIPFile, FileName[ 1 ], L_Get, L_Got );
  312.  
  313.                                    (* Check for I/O error *)
  314.  
  315.                   IF ( ( IOResult <> 0 ) OR ( L_Get<> L_Got ) ) THEN
  316.                      Error := Format_Error
  317.                   ELSE
  318.                      BEGIN
  319.                                    (* Position to next header *)
  320.  
  321.                         ZIP_Pos := ZIP_Pos + ZIP_Entry.ExtraFieldLength   +
  322.                                              ZIP_Entry.CommentFieldLength +
  323.                                              ZIP_Entry.FileNameLength     +
  324.                                              SIZEOF( Zip_Central_Header_Type );
  325.  
  326.                                    (* Set length of file name *)
  327.  
  328.                         FileName[ 0 ] := CHR( L_Got );
  329.  
  330.                      END;
  331.  
  332.                END
  333.                                    (* Check for end of directory *)
  334.  
  335.             ELSE IF ( ZIP_Entry.Signature = ZIP_End_Central_Dir_Signature ) THEN
  336.                Error := End_Of_File
  337.  
  338.                                    (* Anything else is bogus *)
  339.             ELSE
  340.                Error := Format_Error;
  341.  
  342.       END;
  343.  
  344.    Get_Next_ZIP_Entry := ( Error = 0 );
  345.  
  346. END   (* Get_Next_ZIP_Entry *);
  347.  
  348. (*----------------------------------------------------------------------*)
  349. (*   Find_ZIP_Central_Directory --- Find central ZIP file directory     *)
  350. (*----------------------------------------------------------------------*)
  351.  
  352. FUNCTION Find_ZIP_Central_Directory( VAR Error : INTEGER ) : BOOLEAN;
  353.  
  354. (*----------------------------------------------------------------------*)
  355. (*                                                                      *)
  356. (*    Function:  Find_ZIP_Central_Directory                             *)
  357. (*                                                                      *)
  358. (*    Purpose:   Finds central ZIP file directory                       *)
  359. (*                                                                      *)
  360. (*    Calling sequence:                                                 *)
  361. (*                                                                      *)
  362. (*       OK := Find_ZIP_Central_Directory( VAR Error : INTEGER ) :      *)
  363. (*                BOOLEAN;                                              *)
  364. (*                                                                      *)
  365. (*          Error    --- Error flag                                     *)
  366. (*          OK       --- TRUE if header successfully found, else FALSE  *)
  367. (*                                                                      *)
  368. (*----------------------------------------------------------------------*)
  369.  
  370. VAR
  371.    I             : INTEGER;
  372.    J             : INTEGER;
  373.    L             : LONGINT;
  374.    ZIP_Local_Hdr : ZIP_Local_Header_Type   (* Local header         *);
  375.  
  376. BEGIN (* Find_ZIP_Central_Directory *)
  377.  
  378.                                    (* Assume no error to start          *)
  379.    Error   := 0;
  380.                                    (* Start at beginning of file.       *)
  381.    ZIP_Pos := 0;
  382.                                    (* Begin loop over local headers.    *)
  383.  
  384.                                    (* Report success/failure to calling *)
  385.                                    (* routine.                          *)
  386.  
  387.    WHILE ( Get_Next_ZIP_Local_Header( ZIP_Local_Hdr , Error ) ) DO;
  388.  
  389.    Find_ZIP_Central_Directory := ( Error = Central_Dir_Found );
  390.  
  391. END   (* Find_ZIP_Central_Directory *);
  392.  
  393. (*----------------------------------------------------------------------*)
  394. (*        Display_ZIP_Entry --- Display ZIP file file entry info        *)
  395. (*----------------------------------------------------------------------*)
  396.  
  397. PROCEDURE Display_ZIP_Entry( ZIP_Entry : ZIP_Central_Header_Type ;
  398.                              File_Name : String           );
  399.  
  400. VAR
  401.    I         : INTEGER;
  402.    L         : INTEGER;
  403.    FName     : String;
  404.    TimeDate  : LONGINT;
  405.    TimeDateW : ARRAY[1..2] OF WORD ABSOLUTE TimeDate;
  406.  
  407. BEGIN (* Display_ZIP_Entry *)
  408.  
  409.    WITH ZIP_Entry DO
  410.       BEGIN
  411.                                    (* Pick up short file name.  Look *)
  412.                                    (* for trailing '/', and extract  *)
  413.                                    (* stuff beyond as file name.     *)
  414.          FName := File_Name;
  415.  
  416.          I     := POS( '/' , FName );
  417.  
  418.          IF ( I > 0 ) THEN
  419.             BEGIN
  420.  
  421.                L := LENGTH( FName );
  422.  
  423.                WHILE( FName[ L ] <> '/' ) DO
  424.                   DEC( L );
  425.  
  426.                DELETE( FName, 1, L );
  427.  
  428.             END;
  429.  
  430.                                    (* Get date and time of creation *)
  431.  
  432.          TimeDateW[ 1 ] := FileTime;
  433.          TimeDateW[ 2 ] := FileDate;
  434.  
  435.                                    (* Display this entry's information *)
  436.          INC (FileNdx);
  437.          ListArray[FileNdx].Name   := FName;
  438.          ListArray[FileNdx].ASize  := CompressedSize;
  439.          ListArray[FileNdx].Place  := 0;
  440.          ListArray[FileNdx].OSize  := UnCompressedSize;
  441.          ListArray[FileNdx].Date   := FileDate;
  442.          ListArray[FileNdx].Time   := FileTime;
  443.          ListArray[FileNdx].Group  := 0;
  444.       END;
  445.  
  446. END (* Display_ZIP_Entry *);
  447.  
  448. (*----------------------------------------------------------------------*)
  449.  
  450. BEGIN (* Display_ZIP_Contents *)
  451.                                    (* Open ZIP file and initialize *)
  452.                                    (* contents display.            *)
  453.  
  454.                                    (* Skip to central directory in ZIP file *)
  455.  
  456.          IF Find_ZIP_Central_Directory( Ierr ) THEN
  457.  
  458.                                    (* Loop over entries      *)
  459.  
  460.             WHILE ( Get_Next_ZIP_Entry( ZIP_Entry , File_Name , Ierr ) ) DO
  461.                Display_ZIP_Entry( ZIP_Entry , File_Name )
  462.  
  463.          ELSE
  464.                WRITELN( 'Failed to find central ZIP directory for ', ZIPFileName );
  465.  
  466.                                    (* Close ZIP file file *)
  467.  
  468. END   (* Display_ZIP_Contents *);
  469.  
  470. {
  471. ┌────────────────────────────────────────────────────┐
  472. │ PROCEDURE Usage                                    │
  473. └────────────────────────────────────────────────────┘
  474. }
  475. PROCEDURE Usage;
  476.  
  477. BEGIN
  478.   CLRSCR;
  479.   WRITELN (Output,
  480. 'ZIPDEL 1.0 (C) 1989 by Ted Stephens ',NL,NL,
  481. 'ZIPDEL is used to clean up a directory by deleting the files that came',NL,
  482. 'out of archive (.ZIP) files, OR (2) clean up an ZIP file by deleting files',NL,
  483. 'in the ZIP file that exist in a directory.',NL,
  484. '',NL,
  485. 'USAGE:     ZIPDEL [zip_file_template]{.ZIP}  {/options}',NL,
  486. '',NL,
  487. 'Options must be listed singly, each one prefixed by the slash ("/")',NL,
  488. 'character AND spaced apart.  The options can be used in any combination.',NL,
  489. '',NL,
  490. 'V :  Verify deletion by asking (yes/no) before deleting each file.',NL,
  491. 'F :  Force delete on matching filename even if there is a mismatch in',NL,
  492. '     creation date, time, or file size.',NL,
  493. 'T :  Test -- no deletions at all, just report what would be deleted. ',NL,
  494. 'D :  Deletes FROM THE ZIP FILE, NOT THE DIRECTORY.',NL);
  495.   Halt;
  496. END;
  497.  
  498. {
  499. ┌────────────────────────────────────────────────────┐
  500. │ PROCEDURE Beep                                     │
  501. └────────────────────────────────────────────────────┘
  502. }
  503.  
  504. PROCEDURE Beep (message : STRING);
  505.  
  506. BEGIN
  507.   WRITELN (Output, NL, message, NL);
  508.   SOUND (560);
  509.   DELAY (50);
  510.   NOSOUND;
  511. END;
  512.  
  513. {
  514. ┌────────────────────────────────────────────────────┐
  515. │ PROCEDURE Error_Message                            │
  516. └────────────────────────────────────────────────────┘
  517. }
  518.  
  519. PROCEDURE Error_Message (message : STRING);
  520.  
  521. BEGIN
  522.   WRITELN (Output, Bell, NL, message, NL);
  523.   HALT;                                     { ding bell & write message }
  524. END;
  525.  
  526. {
  527. ┌────────────────────────────────────────────────────┐
  528. │ PROCEDURE GET_FILENAME_LIST                        │
  529. └────────────────────────────────────────────────────┘
  530. }
  531.  
  532. PROCEDURE Get_FileName_List (InFileSpecV : Line; VAR NamePtrV : NPtr);
  533.  
  534. VAR                               { make list of ZIP files matching  }
  535.   FileRecord : SearchRec;         { InFileSpecV                      }
  536.   P1, P2, P3 : Nptr;
  537.   FirstDir   : BOOLEAN;
  538.   Placed     : BOOLEAN;
  539.  
  540. BEGIN
  541.   FirstDir := True;
  542.   NamePtrV := nil;
  543.   P1       := nil;                { P1 is always "newest" pointer     }
  544.   P2       := nil;                { P2 points to immediate past item  }
  545.   P3       := nil;                { P3 is temp. ptr. for sort routine }
  546.  
  547.   FindFirst (InFileSpecV, AnyFile, FileRecord);
  548.   IF DosError <> 0 THEN
  549.     Error_Message ('No file found matching file specification')
  550.   ELSE
  551.     BEGIN
  552.       WHILE DosError = 0 DO
  553.         BEGIN
  554.           IF FileRecord.Attr <> Directory THEN
  555.             BEGIN
  556.               NEW (P1);
  557.               P1^.Name := FileRecord.Name;
  558.               IF FirstDir = True THEN
  559.                 BEGIN
  560.                   P1^.Next := nil;
  561.                   P1^.Prev := nil;
  562.                   P2       := P1;
  563.                   FirstDir := False;
  564.                 END
  565.               ELSE
  566.                 IF (P1^.Name < P2^.Name) THEN { Sort dir. names }
  567.                     BEGIN
  568.                       P1^.Next    := P2;
  569.                       P1^.Prev    := nil;
  570.                       P2^.Prev    := P1;
  571.                       P2          := P1;
  572.                     END
  573.                   ELSE
  574.                     BEGIN
  575.                       P3     := P2;
  576.                       Placed := False;
  577.                       WHILE ((P3^.Next <> nil) AND (Placed = False)) DO
  578.                         BEGIN
  579.                           IF (P1^.Name >= P3^.Next^.Name) THEN
  580.                             P3 := P3^.Next
  581.                           ELSE
  582.                            Placed := True;
  583.                         END;
  584.                       P1^.Next := P3^.Next;
  585.                       P1^.Prev := P3;
  586.                       P3^.Next^.Prev := P1;
  587.                       P3^.Next := P1;
  588.                     END;
  589.             END;
  590.  
  591.           FindNext (FileRecord);
  592.         END;
  593.  
  594.       NamePtrV := P2;
  595.     END;
  596. END;
  597.  
  598. {
  599. ┌────────────────────────────────────────────────────┐
  600. │ PROCEDURE OPEN_INFILE                              │
  601. └────────────────────────────────────────────────────┘
  602. }
  603.  
  604. PROCEDURE Open_InFile (InFileNameV : Line; VAR InFile : FILE);
  605.  
  606. VAR
  607.   FileAttr : word;
  608.  
  609. BEGIN
  610. {$I-}
  611.   ASSIGN (InFile,InFileNameV);
  612.   IF IOresult <> 0 THEN Error_Message ('Error -- cannot assign filename ' +
  613.                                         InFileNameV);
  614.  
  615.   GetFAttr (InFile, FileAttr);
  616.  
  617.   IF (FileAttr AND Directory) <> 0 THEN
  618.     Error_Message ('Error -- input file ' + InFileNameV +
  619.                    ' does not exist in current directory');
  620.  
  621.   RESET (InFile, 1);
  622.   IF IOresult <> 0 THEN Error_Message ('Error -- cannot open input file ' +
  623.                                         InFileNameV);
  624. {$I+}
  625. END;
  626.  
  627.  
  628. {
  629. ┌────────────────────────────────────────────────────┐
  630. │ PROCEDURE DelFile                                  │
  631. └────────────────────────────────────────────────────┘
  632. }
  633.  
  634. PROCEDURE DelFile (NameV : Line; message : Line);
  635.  
  636. VAR
  637.   DelFile : File;
  638.  
  639. BEGIN
  640.   ASSIGN (DelFile, NameV);
  641.   ERASE (DelFile);
  642.   WRITELN (Output, message);
  643. END;
  644.  
  645.  
  646. {
  647. ┌────────────────────────────────────────────────────┐
  648. │ PROCEDURE Test_for_Del                             │
  649. └────────────────────────────────────────────────────┘
  650. }
  651.  
  652. PROCEDURE Test_for_Del (VAR ListArray : BigArray;
  653.                         DirToCleanV : Line; ZIPCountV : Word;
  654.                         VerifyV, TestV, ForceDelV, DelFromZIPV : BOOLEAN;
  655.                         VAR MatchV : WORD);
  656.  
  657.     {
  658.     ┌────────────────────────────────────────────────────┐
  659.     │ SUB FUNCTION EQUAL                                 │
  660.     └────────────────────────────────────────────────────┘
  661.     }
  662.  
  663.     FUNCTION Equal (VAR first, second; Size : WORD) : BOOLEAN;
  664.     TYPE
  665.       Bytes = ARRAY [0..4] OF BYTE;
  666.     VAR
  667.       n : INTEGER;
  668.     BEGIN
  669.       n     := 0;
  670.       WHILE (n < Size) AND (Bytes(first)[n] = Bytes(second)[n]) DO
  671.         INC (n);
  672.       Equal := n = size;
  673.     END;
  674.  
  675.     {
  676.     ┌────────────────────────────────────────────────────┐
  677.     │ SUB PROCEDURE MARK_ZIP                             │
  678.     └────────────────────────────────────────────────────┘
  679.     }
  680.     PROCEDURE Mark_ZIP (VAR GroupV : BYTE; message : Line);
  681.     BEGIN
  682.       GroupV := 1;
  683.       INC (Match);
  684.       WRITELN (Output, message );
  685.     END;
  686.  
  687. VAR
  688.   i        : INTEGER;
  689.   FileV    : SearchRec;
  690.   OK       : BOOLEAN;
  691.   TmDte    : Time_Date;
  692.   Ch       : CHAR;
  693.   CurFile  : Line;
  694.  
  695. BEGIN
  696.   Match := 0;
  697.   IF FileNdx > 0 THEN
  698.     BEGIN
  699.       IF DirToCleanV = '.\' THEN
  700.         WRITELN (Output, 'Comparing ',InFileName,' to files in current directory',NL)
  701.       ELSE
  702.         WRITELN (Output, 'Comparing ',InFileName,' to files in ',DirToCleanV,NL);
  703.     END;
  704.   FOR i := 1 TO FileNdx DO
  705.     BEGIN
  706.       WRITE (Output, ListArray[i].name,'':12-LENGTH(ListArray[i].name));
  707.       CurFile := DirToCleanV + ListArray[i].name;
  708.       FindFirst (CurFile, AnyFile, FileV);
  709.       IF DosError <> 0 THEN
  710.         WRITELN (Output, ' -- Matching file not found')
  711.       ELSE
  712.         BEGIN
  713.           OK := False;
  714.           MOVE (FileV.Time, TmDte, SizeOf(FileV.Time));
  715.           IF NOT EQUAL (ListArray[i].OSize, FileV.size, 4) THEN
  716.             WRITE (Output, ' -- File size differs')
  717.           ELSE
  718.             IF NOT EQUAL (ListArray[i].date, TmDte[2], 2) THEN
  719.               WRITE (Output, ' -- File date differs')
  720.             ELSE
  721.               IF NOT EQUAL (ListArray[i].time, TmDte[1], 2) THEN
  722.                 WRITE (Output, ' -- File time differs')
  723.               ELSE
  724.                 OK := True;
  725.  
  726.           IF TestV THEN
  727.             IF DelFromZIPV THEN
  728.               WRITELN (Output, ' -- File found, but NOT deleted from ZIP file')
  729.             ELSE
  730.               WRITELN (Output, ' -- File found, but NOT deleted from directory')
  731.           ELSE
  732.             IF VerifyV THEN
  733.               BEGIN
  734.                 WRITE (Output, ' -- Delete file?  (Y or N) ');
  735.                 Ch := ReadKey;
  736.                 IF (Ch = 'y') OR (Ch = 'Y') THEN
  737.                   IF DelFromZIPV THEN
  738.                     Mark_ZIP (ListArray[i].Group,' -- marked')
  739.                   ELSE
  740.                     DelFile (CurFile,' -- File deleted')
  741.                 ELSE
  742.                   WRITELN (Output);
  743.               END
  744.             ELSE
  745.               IF ForceDelV THEN
  746.                 IF DelFromZIPV THEN
  747.                   Mark_ZIP (ListArray[i].Group,' -- File marked for deletion')
  748.                 ELSE
  749.                   DelFile (CurFile,' -- File deleted')
  750.               ELSE
  751.                 IF OK THEN
  752.                   IF DelFromZIPV THEN
  753.                      Mark_ZIP (ListArray[i].Group,' -- File marked for deletion')
  754.                   ELSE
  755.                     DelFile (CurFile,' -- File deleted')
  756.                 ELSE
  757.                   WRITELN (Output,' -- file NOT deleted');
  758.         END;
  759.     END;
  760.  
  761.     IF TestV AND NOT DelFromZIPV THEN
  762.       WRITELN (Output,NL,'Test specified -- directory files not deleted');
  763. END;
  764.  
  765. {
  766. ┌────────────────────────────────────────────────────┐
  767. │ PROCEDURE Read_Params                              │
  768. └────────────────────────────────────────────────────┘
  769. }
  770.  
  771. PROCEDURE Read_Params (VAR InFileSpecV : Line;
  772.                        VAR InPathV     : Line;
  773.                        VAR DirToCleanV : Line;
  774.                        VAR VerifyV     : BOOLEAN;
  775.                        VAR ForceDelV   : BOOLEAN;
  776.                        VAR TestV       : BOOLEAN;
  777.                        VAR DelFromZIPV : BOOLEAN);
  778.  
  779.  
  780. VAR
  781.   Param2 : Line;
  782.   i      : INTEGER;
  783.  
  784. BEGIN
  785.  
  786.   VerifyV     := No;
  787.   ForceDelV   := No;
  788.   TestV       := No;
  789.   DelFromZIPV := No;
  790.   DirToClean  := '.\';
  791.   i           := 0;
  792.  
  793.   IF (ParamCount = 0) OR (ParamStr(1) = '?') OR (ParamStr(1) = '/?') THEN
  794.     Usage
  795.   ELSE
  796.     BEGIN
  797.       InFileSpecV   := StUpCase(ParamStr(1));
  798.       InFileSpecV   := DefaultExtension(InFileSpecV,'ZIP');
  799.       InPathV := JustPathName(InFileSpecV);
  800.       IF InPathV = '' then
  801.            InPathV := DirToClean
  802.       ELSE
  803.            InPathV := InPathV + '\';
  804.       FOR i := 2 TO ParamCount DO
  805.         BEGIN
  806.           Param2 := StUpCase(ParamStr(i));
  807.           IF Param2[1] = '/' THEN
  808.             CASE Param2[2] OF
  809.               'V' :  VerifyV     := Yes;
  810.               'F' :  ForceDelV   := Yes;
  811.               'T' :  TestV       := Yes;
  812.               'D' :  DelFromZIPV := Yes;
  813.             END
  814.           ELSE
  815.             DirToCleanV := Param2 + '\';
  816.         END;
  817.         DirToCleanV := InPathV ;
  818.     END;
  819. END;
  820.  
  821. Procedure BuildNewZip;
  822.  
  823. Const
  824.  
  825.   ZipCommand : String[12] = 'Pkzip -d ';
  826.   ZipResp    : String[12] = 'ZipFile.Rsp';
  827.  
  828. Var
  829.   Response  : TEXT;
  830.   ZipShell  : String;
  831.   i         : Integer;
  832.   DosOk,
  833.   ZipOk,
  834.   MakeZip   : Boolean;
  835.   ZipTD     : Longint;
  836.  
  837. begin
  838.   DosOk  :=No;
  839.   MakeZip:=No;
  840.   ZipOk  :=No;
  841.   GetFTime(InFile,ZipTD);   (* Get time and date of old ZIP *)
  842.   Close(Infile);            (* Close file before shell      *)
  843.   IF Match = 0 THEN
  844.     BEGIN
  845.       WRITELN (Output);
  846.       IF TEST THEN
  847.         WRITELN (Output, 'Test specified -- ZIP file not changed')
  848.       ELSE
  849.         WRITELN (Output, 'No matching files in ZIP to delete');
  850.       EXIT;
  851.     END;
  852.   IF Match = FileNdx THEN
  853.     BEGIN
  854.        WRITELN (Output);
  855.        DelFile (InPath + InFileName,
  856.                'All files in ZIP file match -- ZIP file is deleted');
  857.       EXIT;
  858.     END;
  859.   Assign(Response,InPath + ZipResp);
  860.   Rewrite(Response);
  861.   for i := 1 to FileNdx Do
  862.     Begin
  863.       If ListArray[i].Group = 1 then
  864.          Begin
  865.            Writeln(Response,ListArray[i].Name);
  866.            MakeZip:=Yes;
  867.          End;
  868.     End;
  869.   Close(Response);
  870.   If MakeZip then
  871.     Begin
  872.       WRITE(Output,NL,InFileName,'':12-LENGTH(InFileName));
  873.       WRITE(Output,' -- ZIPing ');
  874.       ZipShell := ZipCommand + Inpath + InFileName + ' @'+ InPath + ZipResp + ' >NUL';
  875.       DosOk := 0 = ExecDos(ZipShell,True,nil) ;
  876.       ZipOk := 0 = DosExitCode;
  877.     End;
  878.   If DosOk and ZipOk and MakeZip
  879.        then Write(Output,' done.');
  880.   Reset(Infile);                 (* Reopen to set time and date    *)
  881.   SetFTime(InFile,ZipTD);        (* Set time and date same old Zip *)
  882.   Close(InFile);                 (* Close for next Zip file        *)
  883.   DelFile(InPath + ZipResp,'');  (* Delete response file for Pkzip *)
  884. end; { procedure BuildNewZip }
  885.  
  886. {
  887. ┌────────────────────────────────────────────────────┐
  888. │ MAIN PROGRAM                                       │
  889. └────────────────────────────────────────────────────┘
  890. }
  891.  
  892. BEGIN
  893.  
  894.   Version := 'Version 1.0, 3-15-89 -- Public Domain by Ted Stephens';
  895.   MarkFL(HeapPtr);                              { Save the current heap ptr }
  896.  
  897.   ASSIGN (Output,'');
  898.   REWRITE (Output);
  899.  
  900.   Read_Params (InFileSpec, InPath, DirToClean,
  901.                Verify, ForceDel, Test, DelFromZIP);
  902.  
  903.   Get_FileName_List (InFileSpec, NamePtr);
  904.  
  905.   ClrScr;
  906.  
  907.   WHILE NamePtr <> nil DO
  908.     BEGIN
  909.       WRITELN (Output);
  910.  
  911.       FileNdx:=0;
  912.  
  913.       InFileName := NamePtr^.Name;
  914.  
  915.       Open_InFile (InPath + InFileName, InFile);
  916.  
  917.       Display_ZIP_Contents(Inpath + InfileName,InFile);
  918.  
  919.       Test_for_Del (ListArray, DirToClean, ZIPCount,
  920.                     Verify, Test, ForceDel, DelFromZIP, Match);
  921.  
  922.       If DelFromZIP Then
  923.            BuildNewZip;
  924.  
  925.       IF NOT DelFromZip Then CLOSE (InFile);
  926.  
  927.       WRITELN (Output);
  928.     
  929.       NamePtr := NamePtr^.Next;                { get next filename         }
  930.  
  931.     END; {while}
  932.  
  933.   ReleaseFL(HeapPtr);                           { Restore all mem allocated }
  934.  
  935.   Beep ('Processing done.');
  936.  
  937.   CLOSE (Output);
  938.  
  939. END.
  940.